package com.keyue.isolate.handler;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import com.keyue.common.constant.Constant;
import com.keyue.isolate.config.DataIsolateGlobalRefreshConfig;
import com.keyue.isolate.context.DataIsolateContextHolder;
import com.keyue.isolate.context.DataIsolateValue;
import com.keyue.isolate.context.IsolateTableConfigVO;
import com.keyue.isolate.enums.DataIsolateValueTypeEnum;
import com.keyue.isolate.enums.ExpTypeEnum;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.util.cnfexpression.MultiAndExpression;
import net.sf.jsqlparser.util.cnfexpression.MultiOrExpression;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Component
public class SystemDataPermissionHandler implements MultiDataPermissionHandler {

    @Resource
    private DataIsolateGlobalRefreshConfig dataIsolateV2GlobalRefreshConfig;

    /**
     * @param table             表信息
     * @param oriWhere          原始条件
     * @param mappedStatementId 方法id 例如：com.gree.tms.mapper.TmsOrderMapper.selectById
     * @return 最终生成的表达式 返回null代表不需要修改sql语句 否则返回生成的表达式
     */
    @Override
    public Expression getSqlSegment(Table table, Expression oriWhere, String mappedStatementId) {
        if (DataIsolateContextHolder.needIgnoreBefore()) {
            return null;
        }

        List<DataIsolateValue> dataIsolateValues = DataIsolateContextHolder.get();
        if (CollectionUtils.isEmpty(dataIsolateValues)) {
            return null;
        }

        List<Expression> expressions = new ArrayList<>(dataIsolateValues.size());
        for (DataIsolateValue dataIsolateValue : dataIsolateValues) {
            Expression singleExpression = getSingleExpression(
                    dataIsolateValue
                    , Objects.isNull(table.getAlias()) ? "" : table.getAlias().getName() + "."
                    , table
                    , oriWhere
            );
            if (null == singleExpression) {
                //存在一组条件生成的表达式为空 既代表这组条件可以查看全部数据 故直接返回 不需要修改sql
                return null;
            }
            expressions.add(singleExpression);
        }

        return new MultiOrExpression(expressions);
    }

    private Expression getSingleExpression(DataIsolateValue dataIsolateValue, String prefix, Table table, Expression where) {
        String name = table.getName();
        List<IsolateTableConfigVO> configs = dataIsolateV2GlobalRefreshConfig.findConfigsByTableName(name);
        if (CollectionUtils.isEmpty(configs)) {
            return null;
        }

        List<Expression> expressions = new ArrayList<>(configs.size());
        for (IsolateTableConfigVO config : configs) {
            String expType = config.getExpType();
            //根据配置的表达式类型 生成具体的表达式 如InExpression LikeExpression等
            Expression expression = ExpTypeEnum.getDataIsolateExpStragegy(expType).parse(dataIsolateValue, prefix, config);
            if (null == expression) {
                continue;
            }
            expressions.add(expression);
        }

        if (expressions.isEmpty()) {
            //表达式为空代表最终不需生成新的表达式 既：按原始条件查询即可
            return null;
        }


        if (expressions.size() == 1) {
            return new Parenthesis(expressions.get(Constant.ZERO));
        }

        return new MultiAndExpression(expressions);
    }


    /**
     * 根据dataIsolateValueName获取对应的值
     * 由于valueName的值有限 且不太会变 故直接写死 不使用反射或其他方式获取
     *
     * @param dataIsolateValue
     * @param dataIsolateValueName
     * @return
     */
    private List<String> getCodes(DataIsolateValue dataIsolateValue, String dataIsolateValueName) {

        if (DataIsolateValueTypeEnum.CARRIER_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getCarrierCodes();
        }

        if (DataIsolateValueTypeEnum.CUSTOMER_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getCustomerCodes();
        }

        if (DataIsolateValueTypeEnum.CONTRACT_BODY_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getContractBodyCodes();
        }

        if (DataIsolateValueTypeEnum.SOURCE_PLATFORM_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getSourcePlatformCodes();
        }

        if (DataIsolateValueTypeEnum.WAREHOUSE_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getWarehouseCodes();
        }

        if (DataIsolateValueTypeEnum.TRANSPORT_TYPE_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getTransportTypeCodes();
        }

        if (DataIsolateValueTypeEnum.SUB_TRANSPORT_TYPE_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getSubTransportTypeCodes();
        }

        if (DataIsolateValueTypeEnum.COMPANY_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getCompanyCodes();
        }

        if (DataIsolateValueTypeEnum.SIGN_BODY_CODES.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getContractBodyCodes();
        }

        if (DataIsolateValueTypeEnum.FROM_CITY_CODE.getCode().equals(dataIsolateValueName)) {
            return dataIsolateValue.getFromCityCodes();
        }

        return Collections.emptyList();
    }
}
